
package com.ansion.utils.hash;

import android.text.TextUtils;

import com.ansion.log.VLog;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.MessageDigest;


public class HexUtils {
    static char[] symbols = new char[]{
            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
    };

    public static String encode(byte[] buff) {
        return buff == null ? "(null)" : encode(buff, 0, buff.length);
    }

    public static String encode(byte[] buff, int offset, int length) {
        if (buff == null || buff.length < offset + length) {
            return "(null)";
        }

        char[] out = new char[length * 2];

        for (int i = 0; i < length; i++) {
            int base = i + i;
            byte byteData = buff[offset + i];
            out[base] = symbols[(byteData >> 4) & 0x0F];
            out[base + 1] = symbols[byteData & 0x0F];
        }

        return new String(out);
    }

    public static String encode(short[] buff) {
        return encode(buff, 0, buff.length);
    }

    public static String encode(short[] buff, int offset, int length) {
        if (buff == null || buff.length < offset + length) {
            return null;
        }

        char[] out = new char[length * 4];

        for (int i = 0; i < length; i++) {
            int base = i + i + i + i;
            short byteData = buff[offset + i];
            out[base + 0] = symbols[(byteData >> 12) & 0x0F];
            out[base + 1] = symbols[(byteData >> 8) & 0x0F];
            out[base + 2] = symbols[(byteData >> 4) & 0x0F];
            out[base + 3] = symbols[(byteData >> 0) & 0x0F];
        }

        return new String(out);
    }

    public static String byteToHexString(int byteData) {
        char[] out = new char[2];
        out[0] = symbols[(byteData >> 4) & 0x0F];
        out[1] = symbols[byteData & 0x0F];
        return new String(out);
    }

    public static String intToHexString(int intData) {
        char[] out = new char[8];

        for (int i = 0; i < out.length; i++) {
            out[i] = symbols[(intData >> (4 * (7 - i))) & 0x0F];
        }

        return new String(out);
    }

    public static byte[] intToByteArray(int intData) {
        byte[] out = new byte[4];
        for (int i = 0; i < out.length; i++) {
            out[i] = (byte) ((intData >> (8 * (3 - i))) & 0xff);
        }
        return out;
    }

    public static String longToHexString(long longData) {
        char[] out = new char[16];

        for (int i = 0; i < out.length; i++) {
            out[i] = symbols[(int) ((longData >> (4 * (15 - i))) & 0x0F)];
        }

        return new String(out);
    }

    public static byte[] longToByteArray(long longData) {
        byte[] out = new byte[8];
        for (int i = 0; i < out.length; i++) {
            out[i] = (byte) ((longData >> (8 * (7 - i))) & 0xff);
        }
        return out;
    }

    public static long byteArrayToLong(byte[] data) {
        if (data == null || data.length == 0) {
            return 0;
        }

        long result = 0;
        int range = Math.min(data.length, 8);
        for (int i = 0; i < range; i++) {
            result = (result << 8) | (data[i] & 0xff);
        }
        return result;
    }

    public static int byteArrayToInt(byte[] data) {
        if (data == null || data.length == 0) {
            return 0;
        }

        int result = 0;
        int range = Math.min(data.length, 4);
        for (int i = 0; i < range; i++) {
            result = (result << 8) | (data[i] & 0xff);
        }
        return result;
    }

    public static byte[] hexStringToByteArray(String hexEncodedString) {
        if (TextUtils.isEmpty(hexEncodedString)) {
            throw new RuntimeException("Bad input: null pointer");
        }

        final char[] srcStr = hexEncodedString.toCharArray();

        if (srcStr == null || srcStr.length % 2 == 1) {
            throw new RuntimeException("Bad input: length == " + hexEncodedString.length());
        }

        final int bytesLen = hexEncodedString.length() / 2;
        byte[] result = new byte[bytesLen];

        for (int i = 0; i < bytesLen; i++) {
            int pos = i << 1;
            int part1 = hexCharToByte(srcStr[pos]);
            int part2 = hexCharToByte(srcStr[pos + 1]);
            result[i] = (byte) (((part1 & 0xff) << 4) | (part2 & 0xff));
        }

        return result;
    }

    private static int hexCharToByte(char ch) {
        if (ch >= '0' && ch <= '9') {
            return ch - '0';
        } else if (ch >= 'a' && ch <= 'f') {
            return ch - 'a' + 10;
        } else if (ch >= 'A' && ch <= 'F') {
            return ch - 'A' + 10;
        } else {
            throw new RuntimeException("Not a hex symbol");
        }
    }

    public static byte[] intToByteArrayDesc(int intData) {
        byte[] out = new byte[4];
        for (int i = 0; i < out.length; i++) {
            out[i] = (byte) ((intData >> (8 * i)) & 0xff);
        }
        return out;
    }

    public static int byteArrayToIntDesc(byte[] data) {
        if (data == null || data.length == 0) {
            return 0;
        }

        int result = 0;
        int range = Math.min(data.length, 4);
        for (int i = 0; i < range; i++) {
            result = ((data[i] & 0xff) << 8 * i) | result;
        }
        return result;
    }

    public static long byteArrayToLongDesc(byte[] data) {
        if (data == null || data.length == 0) {
            return 0;
        }

        long result = 0;
        int range = Math.min(data.length, 8);
        for (int i = 0; i < range; i++) {
            result = ((data[i] & 0xff) << 8 * i) | result;
        }
        return result;
    }


    public static byte[] longToByteArrayDesc(long longData) {
        byte[] out = new byte[8];
        for (int i = 0; i < out.length; i++) {
            out[i] = (byte) ((longData >> (8 * i)) & 0xff);
        }
        return out;
    }


    public static byte[] combine(byte[]... elements) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();

            for (byte[] element : elements) {
                baos.write(element);
            }

            return baos.toByteArray();
        } catch (IOException e) {
            throw new AssertionError(e);
        }
    }

    public static String getMd5(byte[] input) {
        String result = "";
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            md5.update(input);
            byte[] bytes = md5.digest();
            result = HashUtils.binaryToHexString(bytes);
        } catch (Exception e) {
            VLog.e(e, "TAG_BASE_MISC", "failed to cal md5");
        }
        return result;
    }
}
